/**
 * 〈功能简述〉<br>
 * 〈菜单〉
 *
 * @author LiJunYi
 * @create 2019/7/4
 * @since 1.0.0
 */
package com.ljy.system.marvel_sys.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ljy.system.marvel_sys.system.dao.PermissionDao;
import com.ljy.system.marvel_sys.system.dao.UserDao;
import com.ljy.system.marvel_sys.system.dao.UserRoleDao;
import com.ljy.system.marvel_sys.system.model.permission.Permission;
import com.ljy.system.marvel_sys.system.model.user.User;
import com.ljy.system.marvel_sys.system.model.user.UserRole;
import com.ljy.system.marvel_sys.system.service.IPermissionService;
import com.ljy.system.marvel_sys.common.util.dtree.CheckArr;
import com.ljy.system.marvel_sys.common.util.dtree.Dtree;
import com.ljy.system.marvel_sys.common.util.dtree.DtreeUtil;
import com.ljy.system.marvel_sys.common.util.dtree.Status;
import org.apache.shiro.SecurityUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class PermissionServiceImpl implements IPermissionService {

    @Resource
    PermissionDao permissionDao;
    @Resource
    UserRoleDao userRoleDao;
    @Resource
    UserDao userDao;
    @Resource
    private RedisTemplate<String,Object> redisTemplate;

    /**
     * 根据用户id查找该用户的权限，获得菜单以及层级关系,用于用于登录后显示菜单
     * */
    @Override
    public Permission queryPermissionByUser(long userId) {
        // 将用户对于的角色ID作为KEY进行缓存操作。
        UserRole userRole = userRoleDao.selectOne(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId, userId));
        String key = "roleId_"+userRole.getRoleId() + "_redisPermissionRoot";
        Permission redisPermissionRoot = (Permission) redisTemplate.opsForValue().get(key);
        if(null == redisPermissionRoot){
            List<Permission> permissions = permissionDao.queryPermissionByUser(userId);
            Map<Long, Permission> permissionMap = new HashMap<>(200);
            Permission root = null;
            for (Permission permission : permissions) {
                permissionMap.put(permission.getId(), permission);
            }
            for (Permission permission : permissions) {
                Permission child = permission;
                if (child.getPid() == 0) {
                    /*pid=0则为顶级节点*/
                    root = permission;
                } else {
                    /*
                     * permissionMap存入id，若根据pid可查找到数据，则该数据为父菜单，
                     *                       进而可将子级菜单添加进去得到层级关系
                     * */
                    Permission parent = permissionMap.get(child.getPid());
                    parent.getChildren().add(child);
                }
            }
            // 存入缓存
            redisTemplate.opsForValue().set(key, root);
            return root;
        }else{
            return redisPermissionRoot;
        }
    }

    /**
     * 当前角色所分配的菜单  菜单树形结构展示*/
    @Override
    public DtreeUtil queryPermissionByRoleId(Integer roleId) {
        DtreeUtil redisDtreeUtil = (DtreeUtil)redisTemplate.opsForValue().get("roleId_"+roleId+"_redisDtreeUtil");
        if(null == redisDtreeUtil){
            DtreeUtil dtreeUtil = new DtreeUtil();
            /*所有菜单*/
            List<Permission> permissions = permissionDao.selectList(null);
            /*当前角色所分配的菜单*/
            List<Permission> rolePermissions = permissionDao.queryPermissionByRoleId(roleId);
            /*
             * 得到当前角色已分配的许可ID，用于判断复选框是否勾选
             * */
            List<Long> permissionids = new ArrayList<>();
            for (Permission permission : rolePermissions) {
                permissionids.add(permission.getId());
            }
            /*进行格式生成*/
            List<Dtree> dtrees = new ArrayList<>();
            for(Permission p : permissions){
                /*树形类*/
                Dtree dtree = new Dtree();
                /*复选框类*/
                CheckArr checkArr = new CheckArr();
                /*如果角色已分配ID包含这个P，则该P视为已分配*/
                /*主ID*/
                dtree.setId(p.getId());
                /*菜单名称*/
                dtree.setTitle(p.getName());
                /*父ID*/
                dtree.setParentId(p.getPid());
                /*复选框*/
                checkArr.setType("0");
                if(permissionids.contains(p.getId())){
                    checkArr.setChecked("1");
                }else{
                    checkArr.setChecked("0");
                }
                dtree.setCheckArr(checkArr);
                dtrees.add(dtree);
            }
            Status status = new Status();
            dtreeUtil.setStatus(status);
            dtreeUtil.setData(dtrees);
            redisTemplate.opsForValue().set("roleId_"+roleId+"_redisDtreeUtil", dtreeUtil);
            return dtreeUtil;
        }else{
            return redisDtreeUtil;
        }
    }

    /**  用于目录菜单的显示*/
    @Override
    public List<Permission> listPermission() {
        List<Permission> redisPermissions = (List<Permission>) redisTemplate.opsForList().index("listPermission",0);
        if(null == redisPermissions){
            List<Permission> permissionList = permissionDao.selectList(null);
            //缓存不存在 ，存入缓存
            redisTemplate.opsForList().leftPush("listPermission", permissionList);
            return permissionList;
        }else{
            return redisPermissions;
        }

    }

    /**新增目录-菜单方法*/
    @Override
    public int insertPermission(Permission permission) {
        //新增目录或者菜单，需要删除缓存中的数据以便达到同步
        delRedis();
        return permissionDao.insert(permission);
    }

    /** 更新目录菜单方法*/
    @Override
    public int updatePermission(Permission permission) {
        // 更新菜单 需要删除缓存中的数据以便达到同步
        delRedis();
        return permissionDao.updateById(permission);
    }

    /** 删除菜单方法*/
    @Override
    public String deletePermission(int id) {
        int i = permissionDao.deleteById(id);
        if(i > 0){
            // 删除菜单 需要删除缓存中的数据以便达到同步
            delRedis();
            return "ok";
        }else{
            return "delError";
        }
    }

    /** 删除菜单缓存以及用户登录时缓存 公共方法*/
    private void delRedis(){
        // 获取当前登录用户名
        Object userName = SecurityUtils.getSubject().getPrincipal();
        String loginUserName = userName.toString();
        User user = userDao.selectOne(new QueryWrapper<User>().lambda().eq(User::getUserName, loginUserName));
        UserRole userRole = userRoleDao.selectOne(new QueryWrapper<UserRole>().lambda().eq(UserRole::getUserId, user.getId()));
        String key = "roleId_"+userRole.getRoleId() + "_redisPermissionRoot";
        redisTemplate.delete(key);
        redisTemplate.delete("roleId_1_redisDtreeUtil");
        redisTemplate.delete("roleId_3_redisDtreeUtil");
        redisTemplate.delete("listPermission");
    }
}
